
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using UnityEditor;
using UnityEngine;

// 注意：不支持二维数组
// id	客户端版本号	服务器版本号	通知	test
// id	clientVer	serverVer	notice	test
// int	string	string	string	int[]
// 1	1.0.2	1.0.1	hello	4;66;6
// 2	1.0.2	1.0.1	hello	5

namespace ABA
{
    public class ConvertExcelWnd : EditorWindow
    {
        private List<SettingItem> settingItemList;
        private Vector2 scrollPos;
        private GUIStyle titleStyle;

        private GUIStyle infoStyle;

        [MenuItem("ABA/Excel转表工具", false, 1)]
        public static void ConvertExcelConfig()
        {
            GetWindow<ConvertExcelWnd>(false, "转换配表设置", true);
        }

        private void Awake()
        {
            titleStyle = new GUIStyle();
            titleStyle.normal.textColor = Color.red;
            titleStyle.fontStyle = FontStyle.Bold;
            titleStyle.fontSize = 15;

            infoStyle = new GUIStyle();
            infoStyle.fontSize = 14;
            infoStyle.normal.textColor = Color.white;
        }
        private void OnGUI()
        {
            // 配置目录
            EditorGUILayout.BeginHorizontal();
            if (GUILayout.Button("刷新目录", GUILayout.Width(90)))
            {
                Init();
            }

            if (GUILayout.Button("打开设置", GUILayout.Width(90)))
            {
                SettingWnd.ShowWindow(Path_ExcelConfig.TAG);
            }
            EditorGUILayout.EndHorizontal();

            GUILayout.Space(10);
            EditorGUILayout.BeginHorizontal();
            GUILayout.Label("选择", titleStyle, GUILayout.Width(40));
            GUILayout.Label("配表名称", titleStyle, GUILayout.Width(249));
            EditorGUILayout.EndHorizontal();

            scrollPos = EditorGUILayout.BeginScrollView(scrollPos);

            if (settingItemList == null) Init();

            for (int i = 0; i < settingItemList.Count; i++)
            {
                SettingItem item = settingItemList[i];

                GUILayout.BeginHorizontal();
                item.Selected = GUILayout.Toggle(item.Selected, "", GUILayout.Width(40));
                GUILayout.Label(item.Name, infoStyle, GUILayout.Width(249));
                GUILayout.EndHorizontal();
            }
            EditorGUILayout.EndScrollView();

            EditorGUILayout.BeginHorizontal();
            if (GUILayout.Button("转换选中", GUILayout.Height(50)))
            {
                var list = new List<SettingItem>();
                foreach (var item in settingItemList)
                {
                    if (item.Selected)
                        list.Add(item);
                }
                if (list.Count > 0)
                    ConverConfig.GenCSharp(list);
                else
                    EditorUtility.DisplayDialog("提示", "请至少勾选一项", "好吧");
            }
            if (GUILayout.Button("转换全部", GUILayout.Height(50)))
            {
                if (settingItemList.Count > 0)
                    ConverConfig.GenCSharp(settingItemList);

                //WriteSetting();
                AssetDatabase.Refresh();
            }
            if (GUILayout.Button("导入选中数据", GUILayout.Height(50)))
            {
                var list = new List<SettingItem>();
                settingItemList.ForEach((item) =>
                {
                    if (item.Selected)
                        list.Add(item);
                });

                if (list.Count > 0)
                {
                    ImportData(list);
                }
                else
                    EditorUtility.DisplayDialog("提示", "请至少勾选一项", "好吧");
            }
            if (GUILayout.Button("导入所有数据", GUILayout.Height(50)))
            {
                ImportData(settingItemList);
            }
            EditorGUILayout.EndHorizontal();
        }

        public void Init()
        {
            settingItemList = new List<SettingItem>();
            if (Directory.Exists(Path_ExcelConfig.ExcelFolder))
            {
                DirectoryInfo folderInfo = new DirectoryInfo(Path_ExcelConfig.ExcelFolder);
                // FileInfo[] fileInfoArray = folderInfo.GetFiles("*.xlsx", SearchOption.AllDirectories);
                FileInfo[] fileInfoArray = folderInfo.GetFiles("*.xlsx");
                foreach (var file in fileInfoArray)
                {
                    if (file.Name.StartsWith("~$")) continue;

                    var item = new SettingItem(Path_ExcelConfig.ExcelFolder, file.Name);
                    settingItemList.Add(item);
                }
            }
        }

        #region Write ScriptableObject and import Data
        private void ImportData(List<SettingItem> list)
        {
            if (list == null || list.Count == 0) return;

            for (int i = 0; i < list.Count; i++)
            {
                var listData = ConverConfig.GetTableData(list[i]);
                for (int j = 0; j < listData.Count; j++)
                {
                    var data = listData[j];
                    ConvertToAsset(list[i], data);
                }
            }
        }
        private void ConvertToAsset(SettingItem item, ExcelData excelData)
        {
            string assemblyName = Path_ExcelConfig.TableSharpAssemblyName;
            var assembly = Assembly.Load(assemblyName);
            string configClassName = "ABA." + "Config_" + excelData.tableName;
            Type dbType = assembly.GetType(configClassName);
            if (dbType == null)
            {
                Debug.LogError("找不到" + configClassName + "类");
                return;
            }

            if (!Directory.Exists(Path_ExcelConfig.GenCSharpFolder))
                Directory.CreateDirectory(Path_ExcelConfig.GenCSharpFolder);

            if (!Directory.Exists(Path_ExcelConfig.GenAssetFolder))
                Directory.CreateDirectory(Path_ExcelConfig.GenAssetFolder);

            StringBuilder builder = new StringBuilder("Assets");
            builder.Append(Path_ExcelConfig.GenAssetFolder.Substring(Application.dataPath.Length));
            builder.Append("/");
            // builder.Append(item.NameWithoutExtension);
            builder.Append("Config_" + excelData.tableName);
            builder.Append(".asset");
            string assetPath = builder.ToString();
            var asset = AssetDatabase.LoadAssetAtPath(assetPath, dbType);
            if (asset == null)
            {
                var obj = ScriptableObject.CreateInstance(configClassName);

                AssetDatabase.CreateAsset(obj, assetPath);
                asset = AssetDatabase.LoadAssetAtPath(assetPath, dbType);
            }

            //写数据
            //变量名
            List<string> fieldList = excelData._fieldNameList;

            //数据类型
            List<string> typeList = excelData._typeNameList;

            string itemClassName = "ABA." + "Item_" + excelData.tableName;
            Type itemType = assembly.GetType(itemClassName);
            ConstructorInfo constructor = itemType.GetConstructor(Type.EmptyTypes);
            ArrayList dataObj = new ArrayList();
            for (int i = 0, iMax = excelData._valueList.Count; i < iMax; i++)
            {
                string[] line = excelData._valueList[i];
                var itemObj = constructor.Invoke(null);

                for (int j = 0, jMax = typeList.Count; j < jMax; j++)
                {
                    var field = itemType.GetField(fieldList[j]);
                    if (field == null)
                    {
                        Debug.LogError(string.Format("找不到{0}类中{1}属性", itemClassName, fieldList[j]));
                        return;
                    }
                    object valueObj = GetCSharpValue(line[j], field.FieldType, excelData);
                    // Debug.LogFormat("{0}={1}", field.Name, valueObj);
                    field.SetValue(itemObj, valueObj);
                    // if(field.Name == "test" && valueObj != null)
                    // {
                    //     int[,] arraySet = (int[,])field.GetValue(itemObj);
                    //     Debug.Log("34333333333:" + arraySet.GetLength(0) + "," + arraySet.GetLength(1));
                    //     for (int iu = 0; iu < arraySet.GetLength(0); iu++)
                    //     {
                    //         for (int ju = 0; ju < arraySet.GetLength(1); ju++)
                    //         {
                    //             Debug.Log(arraySet[iu, ju] + " ");
                    //         }
                    //     }                        
                    // }

                }
                dataObj.Add(itemObj);
            }
            FieldInfo info = dbType.GetField("list");
            
            Type elementType = dataObj[0].GetType();
            // 创建List<T>的泛型实例
            Type listType = typeof(List<>).MakeGenericType(elementType);
            IList listInstance = (IList)Activator.CreateInstance(listType);
            // 将ArrayList的元素复制到List<T>
            foreach (var iitem in dataObj)
            {
                listInstance.Add(iitem);
            }
            // info.SetValue(asset, dataObj.ToArray(itemType));
            info.SetValue(asset, listInstance);

            EditorUtility.SetDirty(asset);
            AssetDatabase.SaveAssets();
        }

        //333;333
        static string[] ParseYiWeiArray(string str)
        {
            str = str.Replace(" ", "");
            if (string.IsNullOrEmpty(str)) return new string[]{};

            // str = str.Replace("[", "");
            // str = str.Replace("]", "");
            var arr = str.Split(';');

            return arr;
        }

        // ////////// [[434,4545],[22,22],[33,44],[55,556]]
        // 434;4545,22;22,33;44,55;556
        static string[,] ParseEWeiArray(string str)
        {
            str = str.Replace(" ", "");
            if (string.IsNullOrEmpty(str)) return null;

            // str = str.Replace("[[", "");
            // str = str.Replace("]]", "");
            var arr = str.Split(",", StringSplitOptions.RemoveEmptyEntries);

            var ret = new string[arr.Length, arr[0].Split(';').Length];
            for (int i = 0; i < arr.Length; i++)
            {
                var arrr = arr[i].Split(';');
                for (int j = 0; j < arrr.Length; j++)
                {
                    ret[i, j] = arrr[j];
                    // Debug.Log($"{i} x {j}  444444444:" + ret[i][j]);
                }
            }
            return ret;
        }

        protected static object GetCSharpValue(string srcValue, Type type, ExcelData excelData)
        {
            object target;

            switch (type.ToString())
            {
                // ulong
                case "System.UInt64":
                    srcValue = srcValue.Replace(" ", "");
                    if (string.IsNullOrEmpty(srcValue))
                        target = default(ulong);
                    else
                    {
                        ulong ul;
                        if (!ulong.TryParse(srcValue, out ul))
                            throw new InvalidOperationException(excelData.tableName + " " + srcValue + " is not a ulong.");
                        target = ul;
                    }
                    break;

                // int
                case "System.Int32":
                    srcValue = srcValue.Replace(" ", "");
                    if (string.IsNullOrEmpty(srcValue))
                        target = default(int);
                    else
                    {
                        int i;
                        if (!int.TryParse(srcValue, out i))
                            throw new InvalidOperationException(excelData.tableName + " " + srcValue + " is not a int.");
                        target = i;
                    }
                    break;

                // uint
                case "System.UInt32":
                    srcValue = srcValue.Replace(" ", "");
                    if (string.IsNullOrEmpty(srcValue))
                        target = default(uint);
                    else
                    {
                        uint i;
                        if (!uint.TryParse(srcValue, out i))
                            throw new InvalidOperationException(excelData.tableName + " " + srcValue + " is not a uint.");
                        target = i;
                    }
                    break;

                // ushort
                case "System.UInt16":
                    srcValue = srcValue.Replace(" ", "");
                    if (string.IsNullOrEmpty(srcValue))
                        target = default(ushort);
                    else
                    {
                        ushort b;
                        if (!ushort.TryParse(srcValue, out b))
                            throw new InvalidOperationException(string.Format("{0} is not a ushort", srcValue));
                        target = b;
                    }
                    break;

                // byte
                case "System.Byte":
                    srcValue = srcValue.Replace(" ", "");
                    if (string.IsNullOrEmpty(srcValue))
                        target = default(byte);
                    else
                    {
                        byte b;
                        if (!byte.TryParse(srcValue, out b))
                            throw new InvalidOperationException(excelData.tableName + " " + srcValue + " is not a byte.");
                        target = b;
                    }
                    break;

                // float
                case "System.Single":
                    srcValue = srcValue.Replace(" ", "");
                    if (string.IsNullOrEmpty(srcValue))
                        target = default(float);
                    else
                    {
                        float f;
                        if (!float.TryParse(srcValue, out f))
                            throw new InvalidOperationException(excelData.tableName + " " + srcValue + " is not a float.");
                        target = f;
                    }
                    break;

                // double
                case "System.Double":
                    srcValue = srcValue.Replace(" ", "");
                    if (string.IsNullOrEmpty(srcValue))
                        target = default(double);
                    else
                    {
                        double f;
                        if (!double.TryParse(srcValue, out f))
                            throw new InvalidOperationException(excelData.tableName + " " + srcValue + " is not a double.");
                        target = f;
                    }
                    break;

                // string
                case "System.String":
                    target = srcValue.TrimStart('"').TrimEnd('"');
                    break;

                // bool
                case "System.Boolean":
                    if (string.IsNullOrEmpty(srcValue))
                        target = default(bool);
                    else
                    {
                        bool b;
                        if (!bool.TryParse(srcValue.ToLower(), out b))
                            throw new InvalidOperationException(excelData.tableName + " " + srcValue + " is not a boolean.");
                        target = b;
                    }
                    break;


                // ulong
                case "System.UInt64[]":
                    srcValue = srcValue.Replace(" ", "");
                    if (string.IsNullOrEmpty(srcValue))
                        target = default(ulong[]);
                    else
                    {
                        ArrayList dataObj = new ArrayList();
                        string[] line = ParseYiWeiArray(srcValue);
                        for (int j = 0; j < line.Length; j++)
                        {
                            ulong i;
                            if (!ulong.TryParse(line[j], out i))
                                throw new InvalidOperationException(excelData.tableName + " " + line[j] + " is not a ulong.");
                            dataObj.Add(i);
                        }

                        target = dataObj.ToArray(typeof(ulong));
                    }
                    break;

                // int
                case "System.Int32[]":
                    srcValue = srcValue.Replace(" ", "");
                    if (string.IsNullOrEmpty(srcValue))
                        target = default(int[]);
                    else
                    {
                        ArrayList dataObj = new ArrayList();
                        string[] line = ParseYiWeiArray(srcValue);
                        for (int j = 0; j < line.Length; j++)
                        {
                            int i;
                            if (!int.TryParse(line[j], out i))
                                throw new InvalidOperationException(excelData.tableName + " " + line[j] + " is not a int.");
                            dataObj.Add(i);
                        }

                        target = dataObj.ToArray(typeof(int));
                    }
                    break;

                // uint
                case "System.UInt32[]":
                    srcValue = srcValue.Replace(" ", "");
                    if (string.IsNullOrEmpty(srcValue))
                        target = default(uint[]);
                    else
                    {
                        ArrayList dataObj = new ArrayList();
                        string[] line = ParseYiWeiArray(srcValue);
                        for (int j = 0; j < line.Length; j++)
                        {
                            uint i;
                            if (!uint.TryParse(line[j], out i))
                                throw new InvalidOperationException(excelData.tableName + " " + line[j] + " is not a uint.");
                            dataObj.Add(i);
                        }

                        target = dataObj.ToArray(typeof(uint));
                    }
                    break;

                // ushort
                case "System.UInt16[]":
                    srcValue = srcValue.Replace(" ", "");
                    if (string.IsNullOrEmpty(srcValue))
                        target = default(ushort[]);
                    else
                    {
                        ArrayList dataObj = new ArrayList();
                        string[] line = ParseYiWeiArray(srcValue);
                        for (int j = 0; j < line.Length; j++)
                        {
                            ushort i;
                            if (!ushort.TryParse(line[j], out i))
                                throw new InvalidOperationException(excelData.tableName + " " + line[j] + " is not a ushort.");
                            dataObj.Add(i);
                        }

                        target = dataObj.ToArray(typeof(ushort));
                    }
                    break;

                // byte
                case "System.Byte[]":
                    srcValue = srcValue.Replace(" ", "");
                    if (string.IsNullOrEmpty(srcValue))
                        target = default(byte[]);
                    else
                    {
                        ArrayList dataObj = new ArrayList();
                        string[] line = ParseYiWeiArray(srcValue);
                        for (int j = 0; j < line.Length; j++)
                        {
                            byte i;
                            if (!byte.TryParse(line[j], out i))
                                throw new InvalidOperationException(excelData.tableName + " " + line[j] + " is not a byte.");
                            dataObj.Add(i);
                        }

                        target = dataObj.ToArray(typeof(byte));
                    }
                    break;

                // float
                case "System.Single[]":
                    srcValue = srcValue.Replace(" ", "");
                    if (string.IsNullOrEmpty(srcValue))
                        target = default(float[]);
                    else
                    {
                        ArrayList dataObj = new ArrayList();
                        string[] line = ParseYiWeiArray(srcValue);
                        for (int j = 0; j < line.Length; j++)
                        {
                            float i;
                            if (!float.TryParse(line[j], out i))
                                throw new InvalidOperationException(excelData.tableName + " " + line[j] + " is not a float.");
                            dataObj.Add(i);
                        }

                        target = dataObj.ToArray(typeof(float));
                    }
                    break;

                // double
                case "System.Double[]":
                    srcValue = srcValue.Replace(" ", "");
                    if (string.IsNullOrEmpty(srcValue))
                        target = default(double[]);
                    else
                    {
                        ArrayList dataObj = new ArrayList();
                        string[] line = ParseYiWeiArray(srcValue);
                        for (int j = 0; j < line.Length; j++)
                        {
                            double i;
                            if (!double.TryParse(line[j], out i))
                                throw new InvalidOperationException(excelData.tableName + " " + line[j] + " is not a double.");
                            dataObj.Add(i);
                        }

                        target = dataObj.ToArray(typeof(double));
                    }
                    break;

                // string
                case "System.String[]":
                    {
                        srcValue = srcValue.TrimStart('"').TrimEnd('"');
                        ArrayList dataObj = new ArrayList();
                        string[] line = ParseYiWeiArray(srcValue);
                        for (int j = 0; j < line.Length; j++)
                        {
                            dataObj.Add(line[j]);
                        }
                        target = dataObj.ToArray(typeof(string));
                        break;
                    }


                // bool
                case "System.Boolean[]":
                    if (string.IsNullOrEmpty(srcValue))
                        target = default(bool[]);
                    else
                    {
                        ArrayList dataObj = new ArrayList();
                        string[] line = ParseYiWeiArray(srcValue);
                        for (int j = 0; j < line.Length; j++)
                        {
                            bool i;
                            if (!bool.TryParse(line[j], out i))
                                throw new InvalidOperationException(excelData.tableName + " " + line[j] + " is not a bool.");
                            dataObj.Add(i);
                        }

                        target = dataObj.ToArray(typeof(bool));
                    }
                    break;



                // ulong
                case "System.UInt64[,]":
                    srcValue = srcValue.Replace(" ", "");
                    if (string.IsNullOrEmpty(srcValue))
                        target = default(ulong[,]);
                    else
                    {
                        ArrayList dataObj = new ArrayList();
                        string[,] line = ParseEWeiArray(srcValue);
                        for (int j = 0; j < line.GetLength(0); j++)
                        {
                            ArrayList dataObjkk = new ArrayList();
                            for (int k = 0; k < line.GetLength(1); k++)
                            {
                                ulong i;
                                if (!ulong.TryParse(line[j,k], out i))
                                    throw new InvalidOperationException(excelData.tableName + " " + line[j,k] + " is not a ulong.");
                                dataObjkk.Add(i);
                            }
                            dataObj.Add(dataObjkk.ToArray(typeof(ulong)));
                        }
                        target = dataObj.ToArray(typeof(ulong[,]));
                    }
                    break;


                // int
                case "System.Int32[,]":
                    srcValue = srcValue.Replace(" ", "");
                    if (string.IsNullOrEmpty(srcValue))
                        target = default(int[,]);
                    else
                    {
                        string[,] line = ParseEWeiArray(srcValue);
                        var dataObj = new int[line.GetLength(0), line.GetLength(1)];
                        for (int j = 0; j < line.GetLength(0); j++)
                        {
                            for (int k = 0; k < line.GetLength(1); k++)
                            {
                                int i;
                                if (!int.TryParse(line[j,k], out i))
                                    throw new InvalidOperationException(excelData.tableName + " " + line[j,k] + " is not a int.");
                                dataObj[j, k] = i;
                            }
                        }
                        target = dataObj;
                    }
                    break;

                // float
                case "System.Single[,]":
                    srcValue = srcValue.Replace(" ", "");
                    if (string.IsNullOrEmpty(srcValue))
                        target = default(float[,]);
                    else
                    {
                        string[,] line = ParseEWeiArray(srcValue);
                        var dataObj = new float[line.GetLength(0), line.GetLength(1)];
                        for (int j = 0; j < line.GetLength(0); j++)
                        {
                            for (int k = 0; k < line.GetLength(1); k++)
                            {
                                float i;
                                if (!float.TryParse(line[j,k], out i))
                                    throw new InvalidOperationException(excelData.tableName + " " + line[j,k] + " is not a float.");
                                dataObj[j, k] = i;
                            }
                        }
                        target = dataObj;
                    }
                    break;


                // double
                case "System.Double[,]":
                    srcValue = srcValue.Replace(" ", "");
                    if (string.IsNullOrEmpty(srcValue))
                        target = default(double[,]);
                    else
                    {
                        string[,] line = ParseEWeiArray(srcValue);
                        var dataObj = new double[line.GetLength(0), line.GetLength(1)];
                        for (int j = 0; j < line.GetLength(0); j++)
                        {
                            for (int k = 0; k < line.GetLength(1); k++)
                            {
                                double i;
                                if (!double.TryParse(line[j,k], out i))
                                    throw new InvalidOperationException(excelData.tableName + " " + line[j,k] + " is not a double.");
                                dataObj[j, k] = i;
                            }
                        }
                        target = dataObj;
                    }
                    break;

                // bool
                case "System.Boolean[,]":
                    if (string.IsNullOrEmpty(srcValue))
                        target = default(bool[,]);
                    else
                    {
                        string[,] line = ParseEWeiArray(srcValue);
                        var dataObj = new bool[line.GetLength(0), line.GetLength(1)];
                        for (int j = 0; j < line.GetLength(0); j++)
                        {
                            for (int k = 0; k < line.GetLength(1); k++)
                            {
                                bool i;
                                if (!bool.TryParse(line[j,k], out i))
                                    throw new InvalidOperationException(excelData.tableName + " " + line[j,k] + " is not a bool.");
                                dataObj[j, k] = i;
                            }
                        }
                        target = dataObj;
                    }
                    break;


                // string
                case "System.String[,]":
                    {
                        srcValue = srcValue.TrimStart('"').TrimEnd('"');
                        ArrayList dataObj = new ArrayList();
                        string[,] lines = ParseEWeiArray(srcValue);
                        target = lines;
                        break;
                    }



                default:
                    Debug.Log(srcValue);
                    target = srcValue;
                    throw new InvalidOperationException("Unexpected c# type: " + type.ToString());
            }

            return target;
        }

        #endregion
    }
    public class SettingItem
    {
        public string Name;
        public bool Selected = false;   //only for single ExcelToSharp or load single Excel Data; (default:false)


        public string NameWithoutExtension { get { return Path.GetFileNameWithoutExtension(Name); } }

        // public string ConfigClassName { get { return "Config_" + NameWithoutExtension; } }
        // public string ItemClassName { get { return "Item_" + NameWithoutExtension; } }

        public SettingItem(string folder, string name)
        {
            if (string.IsNullOrEmpty(folder))
                throw new ArgumentException("folder is null");
            if (string.IsNullOrEmpty(name))
                throw new ArgumentException("name is null");

            this.Name = name;
        }
    }

}
